#!/bin/bash

set -u

declare -A CMD_BSP_FUNC_ARRAY
CMD_BSP_FUNC_ARRAY["init"]=cmd_bsp_init
CMD_BSP_FUNC_ARRAY["st"]=cmd_bsp_st
CMD_BSP_FUNC_ARRAY["release"]=cmd_bsp_release
CMD_BSP_FUNC_ARRAY["backup"]=cmd_bsp_backup
CMD_BSP_FUNC_ARRAY["restore"]=cmd_bsp_restore

L4T_BSP_FIX_CMD="\treturn"

function cmd_bsp()
{
	echo -e "[DEBUG] ${FUNCNAME} $@"

	if [[ $# -le 0 ]]; then
		echo -e "[ERROR] Must specify a BSP SUB_CMD.\n"
		exit 1
	fi

	local SUB_CMD=$1
	shift

	local key
	local found=0
	for key in ${!CMD_BSP_FUNC_ARRAY[@]}; do
		if [[ ${SUB_CMD} == ${key} ]]; then
			found=1
		fi
	done
	if [[ ${found} -ne 1 ]]; then
		echo -e "[ERROR] Unsupport BSP SUB_CMD: ${SUB_CMD}\n"
		exit 1
	fi

	${CMD_BSP_FUNC_ARRAY[${SUB_CMD}]} $@
}

function cmd_bsp_init()
{
	echo -e "[DEBUG] ${FUNCNAME} $@"

	if [[ ! -d ${L4T_TOP} ]]; then
		local L4T_PKG=${HOME}/Downloads/nvidia/sdkm_downloads/Jetson_Linux_R${L4T_VER}_aarch64.tbz2
		local ROOTFS_PKG=${HOME}/Downloads/nvidia/sdkm_downloads/Tegra_Linux_Sample-Root-Filesystem_R${L4T_VER}_aarch64.tbz2
		if [[ ! -f ${L4T_PKG} ]]; then
			echo -e "[ERROR] JetPack L4T package doesnot exist, please download first:"
			echo -e ">>> ${L4T_PKG}\n"
			exit 1
		fi
		if [[ ! -f ${ROOTFS_PKG} ]]; then
			echo -e "[ERROR] JetPack L4T ROOTFS package doesnot exist, please download first:"
			echo -e ">>> ${ROOTFS_PKG}\n"
			exit 1
		fi

		echo -e "[INFO] Decompress L4T Pakcage: $(basename ${L4T_PKG}) ..."
		mkdir -p $(dirname ${L4T_TOP})
		tar -jxf ${L4T_PKG} -C $(dirname ${L4T_TOP})

		echo -e "[INFO] Decompress ROOTFS Pakcage: $(basename ${ROOTFS_PKG}) ..."
		sudo_cmd "tar -jxf ${ROOTFS_PKG} -C ${L4T_TOP}/rootfs"

		local SECBOOT_PKG=${HOME}/Downloads/nvidia/sdkm_downloads/secureboot_R${L4T_VER}_aarch64.tbz2
		if [[ -f ${SECBOOT_PKG} ]]; then
			echo -e "[INFO] Decompress SECBOOT Pakcage: $(basename ${SECBOOT_PKG}) ..."
			tar -jxf ${SECBOOT_PKG} -C ${L4T_TOP}/..
		else
			echo -e "\n[WARN] The JetPack SECBOOT package doesnot exist."
			echo -e ">>> ${SECBOOT_PKG}"
		fi

		echo -e "\n[INFO] Apply NVIDIA binaries ..."
		sudo_cmd "${L4T_TOP}/apply_binaries.sh"

		local NVIDIA_BSP_PATCH=$(abs_path ${CUR_TOP}/../l4t_bsp_patch/NVIDIA_JetPack${JETPACK_VER}_L4T${L4T_VER}_patch)
		if [[ -d ${NVIDIA_BSP_PATCH} ]]; then
			local NVIDIA_BSP_PATCH_LEVEL=$(abs_path_level ${NVIDIA_BSP_PATCH})
			echo -e "\n[INFO] Apply NVIDIA BSP Patches ..."
			traverse ${NVIDIA_BSP_PATCH} traverse_filter_filename_r ^README traverse_exec_install ${NVIDIA_BSP_PATCH_LEVEL} ${L4T_TOP}
		else
			echo -e "\n[WARN] NVIDIA BSP Patches directory not found:"
			echo -e ">>> ${NVIDIA_BSP_PATCH}"
		fi

		local RK_BSP_PATCH=$(abs_path ${CUR_TOP}/../l4t_bsp_patch/RK_JetPack${JETPACK_VER}_L4T${L4T_VER}_patch)
		if [[ -d ${RK_BSP_PATCH} ]]; then
			local RK_BSP_PATCH_LEVEL=$(abs_path_level ${RK_BSP_PATCH})
			echo -e "\n[INFO] Apply Ritrontek BSP Patches ..."
			traverse ${RK_BSP_PATCH} traverse_filter_none 0 traverse_exec_install ${RK_BSP_PATCH_LEVEL} ${L4T_TOP}
		else
			echo -e "\n[WARN] RK BSP Patches directory not found:"
			echo -e ">>> ${RK_BSP_PATCH}"
		fi

		# Change Kernel Image & dtb directory
		# L4T_TOP/kernel  -> L4T_TOP/kernel_bsp
		mkdir -p ${L4T_TOP}/kernel_bsp/dtb
		mv ${L4T_TOP}/kernel/Image ${L4T_TOP}/kernel_bsp/
		mv ${L4T_TOP}/kernel/dtb/* ${L4T_TOP}/kernel_bsp/dtb/
		ln -sf ${L4T_TOP}/kernel_bsp/Image ${L4T_TOP}/kernel/
		local dtb_bsp_list=$(ls ${L4T_TOP}/kernel_bsp/dtb/{*.dtb,*.dtbo})
		local dtb_bsp
		for dtb_bsp in ${dtb_bsp_list}
		do
			ln -sf ${dtb_bsp} ${L4T_TOP}/kernel/dtb/
		done

		# Disable NVIDIA APT Source
		local NVIDIA_APT_SOURCE_FILE=${L4T_TOP}/rootfs/etc/apt/sources.list.d/nvidia-l4t-apt-source.list
		if [[ -f ${NVIDIA_APT_SOURCE_FILE} ]]; then
			echo -e "\n[INFO] Disable NVIDIA APT Source:"
			echo -e ">>> ${NVIDIA_APT_SOURCE_FILE}"
			sudo_cmd "sed -i \"s/^deb/#deb/g\" ${NVIDIA_APT_SOURCE_FILE}"
		fi

		# Remove MTTCAN modprobe blacklist
		local MODPROBE_BLACKLIST_MTTCAN=$(ls ${L4T_TOP}/rootfs/etc/modprobe.d/*mttcan.conf)
		if [[ -f ${MODPROBE_BLACKLIST_MTTCAN} ]]; then
			echo -e "\n[INFO] Remove MTTCAN modprobe blacklist:"
			echo -e ">>> ${MODPROBE_BLACKLIST_MTTCAN}"
			sudo_cmd "sed -i \"s/^blacklist/#blacklist/g\" ${MODPROBE_BLACKLIST_MTTCAN}"
		fi

		echo -e "\n[INFO] L4T BSP directory init successfully.\n"
	else
		echo -e "\n[INFO] L4T BSP directory has already init successfully.\n"
	fi
}

function cmd_bsp_st()
{
	echo -e "[DEBUG] ${FUNCNAME} $@"
	if [[ ! -d ${L4T_TOP} ]]; then
		echo -e "[ERROR] L4T BSP Directory does exist, please init first."
		return
	fi

	local jetson_conf_file=${L4T_TOP}/${JETSON_CONF}.conf
	local jetson_dtb=$(conf1_get ${jetson_conf_file} "DTB_FILE")
	local jetson_dtb_file=${L4T_TOP}/kernel/dtb/${jetson_dtb}
	local jetson_kernel_file=${L4T_TOP}/kernel/Image

	source ${CUR_TOP}/helper/helper_cmd_src.sh
	local jetson_kernel_bsp_bak="${L4T_TOP}/kernel_bsp/Image"
	local jetson_kernel_src_bak="${L4T_TOP}/kernel_src/Image"
	local jetson_kernel_src_output="${L4T_SRC_OUTPUT_TOP}/arch/arm64/boot/Image"
	local jetson_dtb_bsp_bak="${L4T_TOP}/kernel_bsp/dtb/${jetson_dtb}"
	local jetson_dtb_src_bak="${L4T_TOP}/kernel_src/dtb/${jetson_dtb}"
	if [[ ${L4T_VER_MAJOR} -lt 35 ]]; then
		local jetson_dtb_src_output="${L4T_SRC_OUTPUT_TOP}/arch/arm64/boot/dts/${jetson_dtb}"
	else
		local jetson_dtb_src_output="${L4T_SRC_OUTPUT_TOP}/arch/arm64/boot/dts/nvidia/${jetson_dtb}"
	fi

	echo -e "- JetPack : ${JETPACK_VER}"
	echo -e "- L4T     : ${L4T_VER}"
	echo -e "- L4T TOP : ${L4T_TOP}"
	printf  "\U2D Jetson Module    : %-13s  (%s)\n" ${JETSON_MODULE} "$(conf2_get_module_name_list ${JETSON_MODULE})"
	printf  "\U2D Jetson Board     : %-13s  (%s)\n" ${JETSON_BOARD}  "$(conf2_get_board_desc ${JETSON_BOARD})"

	if [[ -f ${jetson_conf_file} ]]; then
		echo -e "- Jetson Conf   \033[1;32m[Y]\033[0;37m: ${jetson_conf_file}"
	else
		echo -e "- Jetson Conf   \033[1;31m[N]\033[0;37m: ${jetson_conf_file}"
	fi

	if [[ -f ${jetson_kernel_file} ]]; then
		echo -e "- Jetson Kernel \033[1;32m[Y]\033[0;37m: ${jetson_kernel_file}"
	else
		echo -e "- Jetson Kernel \033[1;31m[N]\033[0;37m: ${jetson_kernel_file}"
	fi
	if [[ $(readlink ${jetson_kernel_file}) == "${jetson_kernel_bsp_bak}" ]]; then
		echo -e "     \033[1;34mSymbolic Link to BSP\033[0;37m"
		echo -e "     ---> ${jetson_kernel_bsp_bak}"
	elif [[ $(readlink ${jetson_kernel_file}) == "${jetson_kernel_src_bak}" ]]; then
		echo -e "     \033[1;32mSymbolic Link to SRC\033[0;37m"
		local inode_bak=$(get_inode ${jetson_kernel_src_bak})
		local inode_output=$(get_inode ${jetson_kernel_src_output})
		if [[ ${inode_bak} == ${inode_output} ]]; then
			echo -e "     ---> [${inode_bak}] ${jetson_kernel_src_bak}"
			echo -e "     ---> [${inode_output}] ${jetson_kernel_src_output}"
		else
			echo -e "     \033[1;33mWARN, Kernel Image File Inode Mismatch!\033[0;37m"
			echo -e "     ---> \033[1;33m[${inode_bak}]\033[0;37m ${jetson_kernel_src_bak}"
			echo -e "     ---> \033[1;33m[${inode_output}]\033[0;37m ${jetson_kernel_src_output}"
		fi
	else
		echo -e "     \033[1;31mUnknown Symbolic Link\033[0;37m"
		echo -e "     ---> $(readlink ${jetson_kernel_file})"
	fi

	if [[ -f ${jetson_dtb_file} ]]; then
		echo -e "- Jetson DTB    \033[1;32m[Y]\033[0;37m: ${jetson_dtb_file}"
	else
		echo -e "- Jetson DTB    \033[1;31m[N]\033[0;37m: ${jetson_dtb_file}"
	fi
	if [[ $(readlink ${jetson_dtb_file}) == "${jetson_dtb_bsp_bak}" ]]; then
		echo -e "     \033[1;34mSymbolic Link to BSP\033[0;37m"
		echo -e "     ---> ${jetson_dtb_bsp_bak}"
	elif [[ $(readlink ${jetson_dtb_file}) == "${jetson_dtb_src_bak}" ]]; then
		echo -e "     \033[1;32mSymbolic Link to SRC\033[0;37m"
		local inode_bak=$(get_inode ${jetson_dtb_src_bak})
		local inode_output=$(get_inode ${jetson_dtb_src_output})
		if [[ ${inode_bak} == ${inode_output} ]]; then
			echo -e "     ---> [${inode_bak}] ${jetson_dtb_src_bak}"
			echo -e "     ---> [${inode_output}] ${jetson_dtb_src_output}"
		else
			echo -e "     \033[1;33mWARN, DTB File Inode Mismatch!\033[0;37m"
			echo -e "     ---> \033[1;33m[${inode_bak}]\033[0;37m ${jetson_dtb_src_bak}"
			echo -e "     ---> \033[1;33m[${inode_output}]\033[0;37m ${jetson_dtb_src_output}"
		fi
	else
		echo -e "     \033[1;31mUnknown Symbolic Link\033[0;37m"
		echo -e "     ---> $(readlink ${jetson_dtb_file})"
	fi

	echo -e "- Jetson VerMagic  : $(get_cur_kernel_vermagic)"
	echo -e ""
}

function cmd_bsp_release()
{
	echo -e "[DEBUG] ${FUNCNAME} $@"
	if [[ ! -d ${L4T_TOP} ]]; then
		echo -e "[ERROR] L4T BSP Directory does exist, please init first.\n"
		return
	fi

	if [[ ! ${JETSON_BOARD} =~ ^rk ]]; then
		echo -e "[ERROR] This function only support Ritrontek Board.\n"
		exit 1
	fi

	local RK_VER_SUFFIX=$(get_kernel_vermagic_rksuffix $(get_cur_kernel_vermagic))
	if [[ -z ${RK_VER_SUFFIX} ]]; then
		echo -e "[ERROR] Current released kernel version magic doesnot included \"RK_VER_SUFFIX\"\n"
		exit 1
	fi

	local jetson_conf_file=${L4T_TOP}/${JETSON_CONF}.conf
	if [[ ! -f ${jetson_conf_file} ]]; then
		echo -e "[ERROR] The Jetson Board Conf file doesnot exist:"
		echo -e ">>> ${jetson_conf_file}\n"
		exit 1
	fi
	local jetson_dtb=$(conf1_get "${jetson_conf_file}" "DTB_FILE")
	local jetson_dtb_file=${L4T_TOP}/kernel/dtb/${jetson_dtb}
	if [[ ! -f ${jetson_dtb_file} ]]; then
		echo -e "[ERROR] The Jetson Board DTB file doesnot exist:"
		echo -e ">>> ${jetson_dtb_file}\n"
		exit 1
	fi

	echo -e "[INFO] Choose which type rootfs released into package:"
	echo -e ">>> [1-none      ] do not release rootfs"
	echo -e ">>> [2-rootfs    ] release rootfs from the L4T BSP roofs directory"
	echo -e ">>> [3-system.img] release rootfs system.img reading from the Jetson Device"
	read -p "Please input \"1, 2, 3\" to select: " key
	while [[ ${key} != "1" ]] \
		&& [[ ${key} != "2" ]] \
		&& [[ ${key} != "3" ]];
	do
		echo -e "\n[ERROR] Input error!"
		read -p "Please input \"1, 2, 3\" to select: " key
	done

	local L4T_FLASH_OPT=
	local L4T_FLASH_TARGET=mmcblk0p1
	case ${key} in
	"1")
		echo -e "[INFO] Selected 1-none. Do not release rootfs"
		local L4T_RELEASE_ROOTFS=none
		local L4T_RELEASE_PKG=Ritrontek_NOROOTFS_JetPack${JETPACK_VER}_L4T${L4T_VER}_${JETSON_MODULE}_${JETSON_BOARD}_${RK_VER_SUFFIX}.tbz2
		L4T_FLASH_TARGET=nvme0n1p1
		;;
	"2")
		echo -e "[INFO] Selected 2-rootfs"
		local L4T_RELEASE_ROOTFS=rootfs
		local L4T_RELEASE_PKG=Ritrontek_ROOTFS_JetPack${JETPACK_VER}_L4T${L4T_VER}_${JETSON_MODULE}_${JETSON_BOARD}_${RK_VER_SUFFIX}.tbz2
		;;
	"3")
		echo -e "[INFO] Selected 3-system.img"
		local L4T_RELEASE_ROOTFS=system.img
		local L4T_RELEASE_PKG=Ritrontek_IMG_JetPack${JETPACK_VER}_L4T${L4T_VER}_${JETSON_MODULE}_${JETSON_BOARD}_${RK_VER_SUFFIX}.tbz2
		L4T_FLASH_OPT="-r"

		if [[ $(check_device_recovery) != "Y" ]]; then
			echo -e "[INFO] Please connect the target Jetson Device to HOST, and put it into recovery mode."
			read -p "Press any key to continue ..." key

			if [[ $(check_device_recovery) != "Y" ]]; then
				echo -e "[ERROR] Jetson Board does not connect, cannot clone \"system.img\", exit!"
				exit 1
			fi
		fi
		;;
	*)
		echo -e "\n[ERROR] Input error!\n"
		exit 1
		;;
	esac

	local L4T_RELEASE_DIR=$(echo ${L4T_RELEASE_PKG:0:${#L4T_RELEASE_PKG}-5})

	echo -e "[INFO] Release L4T BSP into a package:"
	if [[ -f ${L4T_RELEASE_PKG} ]]; then
		rm ${L4T_RELEASE_PKG}
	fi
	if [[ -d ${L4T_RELEASE_DIR} ]]; then
		rm -rf ${L4T_RELEASE_DIR}/*
	else
		mkdir ${L4T_RELEASE_DIR}
	fi

	echo -e "[INFO] Package files ...\n"

	# rootfs/system.img
	if [[ ${L4T_RELEASE_ROOTFS} == "rootfs" ]]; then
		release_file=${L4T_RELEASE_DIR}/resources/rootfs.tbz2
		echo -e "[INFO] >>> ${release_file}"
		sudo_cmd "tar -jcf ${release_file} -C ${L4T_TOP} rootfs"
	elif [[ ${L4T_RELEASE_ROOTFS} == "system.img" ]]; then
		release_file=${L4T_RELEASE_DIR}/resources/bootloader/system.img
		echo -e "[INFO] Clone \"system.img\" from the target Jetson Devcie mmcblk0p1 ..."
		cd ${L4T_TOP}
		sudo_cmd "./flash.sh -r -k APP -G released_system.img ${JETSON_CONF} mmcblk0p1"
		ret=$?
		cd - &>/dev/null
		if [[ ${ret} != 0 ]]; then
			echo -e "\n[ERROR] Clone the target Jetson Devcie APP error, exit!"
			sudo_cmd "rm -rf ${L4T_RELEASE_DIR}"
			exit 1
		fi

		echo -e "\n[INFO] >>> ${release_file}"
		mkdir -p $(dirname ${release_file})
		mv ${L4T_TOP}/released_system.img ${release_file}
	fi

	# kernel
	release_file=${L4T_RELEASE_DIR}/resources/kernel/Image
	echo -e "[INFO] >>> ${release_file}"
	mkdir -p $(dirname ${release_file})
	cp ${L4T_TOP}/kernel/Image ${release_file}

	# dtb
	release_file=${L4T_RELEASE_DIR}/resources/kernel/dtb/${jetson_dtb}
	echo -e "[INFO] >>> ${release_file}"
	mkdir -p $(dirname ${release_file})
	cp ${jetson_dtb_file} ${release_file}

	# conf
	local release_file=${L4T_RELEASE_DIR}/resources/${JETSON_CONF}.conf
	echo -e "[INFO] >>> ${release_file}"
	mkdir -p $(dirname ${release_file})
	cp ${jetson_conf_file} ${release_file}

	# mb1 pinmux
	local mb1_pinmux=$(conf1_get "${jetson_conf_file}" "PINMUX_CONFIG")
	local mb1_pinmux_file=${L4T_TOP}/bootloader/t186ref/BCT/${mb1_pinmux}
	if [[ -n ${mb1_pinmux} && -f ${mb1_pinmux_file} ]]; then
		release_file=${L4T_RELEASE_DIR}/resources/bootloader/t186ref/BCT/${mb1_pinmux}
		echo -e "[INFO] >>> ${release_file}"
		mkdir -p $(dirname ${release_file})
		cp ${mb1_pinmux_file} ${release_file}

		# mb1 pinmux gpio
		local mb1_pinmux_gpio=$(grep "ritrontek-mb1-bct-gpio" ${mb1_pinmux_file} | awk '{print $2}' | xargs echo)
		local mb1_pinmux_gpio_file=${L4T_TOP}/bootloader/${mb1_pinmux_gpio}
		if [[ -n ${mb1_pinmux_gpio} && -f ${mb1_pinmux_gpio_file} ]]; then
			release_file=${L4T_RELEASE_DIR}/resources/bootloader/${mb1_pinmux_gpio}
			echo -e "[INFO] >>> ${release_file}"
			mkdir -p $(dirname ${release_file})
			cp ${mb1_pinmux_gpio_file} ${release_file}
		fi
	fi

	# mb1 pmc
	local mb1_pmc=$(conf1_get "${jetson_conf_file}" "PMC_CONFIG")
	local mb1_pmc_file=${L4T_TOP}/bootloader/t186ref/BCT/${mb1_pmc}
	if [[ -n ${mb1_pmc} && -f ${mb1_pmc_file} ]]; then
		release_file=${L4T_RELEASE_DIR}/resources/bootloader/t186ref/BCT/${mb1_pmc}
		echo -e "[INFO] >>> ${release_file}"
		mkdir -p $(dirname ${release_file})
		cp ${mb1_pmc_file} ${release_file}
	fi

	# mb2 bct
	local mb2_bct=$(conf1_get "${jetson_conf_file}" "MB2_BCT")
	local mb2_bct_file=${L4T_TOP}/bootloader/t186ref/BCT/${mb2_bct}
	if [[ -n ${mb2_bct} && -f ${mb2_bct_file} ]]; then
		release_file=${L4T_RELEASE_DIR}/resources/bootloader/t186ref/BCT/${mb2_bct}
		echo -e "[INFO] >>> ${release_file}"
		mkdir -p $(dirname ${release_file})
		cp ${mb2_bct_file} ${release_file}
	fi

	local L4T_FLASH_CMD
	if [[ ${L4T_RELEASE_ROOTFS} == "none" ]]; then
		L4T_FLASH_CMD="sudo ./tools/kernel_flash/l4t_initrd_flash.sh ${L4T_FLASH_OPT} ${JETSON_CONF} ${L4T_FLASH_TARGET}"
	else
		L4T_FLASH_CMD="sudo ./flash.sh ${L4T_FLASH_OPT} ${JETSON_CONF} ${L4T_FLASH_TARGET}"
	fi

	# copy rk_pkg_tools into release package
	release_file=${L4T_RELEASE_DIR}/install.sh
	echo -e "[INFO] >>> ${release_file}"
	cp ${CUR_TOP}/../l4t_rk_pkg_tools/install.sh ${release_file}
	sed -i "s|<_L4T_FLASH_CMD_>|${L4T_FLASH_CMD}|g" ${release_file}
	sed -i "s|<_L4T_BSP_FIX_CMD_>|${L4T_BSP_FIX_CMD}|g" ${release_file}
	chmod a+x ${release_file}

	# copy README.md into release package
	release_file=${L4T_RELEASE_DIR}/README.md
	echo -e "[INFO] >>> ${release_file}"
	cp ${CUR_TOP}/../l4t_rk_pkg_tools/README.md ${release_file}
	sed -i "s/<_JETPACK_VER_>/${JETPACK_VER}/g" ${release_file}
	local _L4T_TOP_SUBSTR_="~/$(echo ${L4T_TOP} | cut -d/ -f4-)"
	sed -i "s|<_L4T_TOP_>|${_L4T_TOP_SUBSTR_}|g" ${release_file}
	sed -i "s/<_RK_BSP_PKG_DIR_>/${L4T_RELEASE_DIR}/g" ${release_file}
	sed -i "s|<_L4T_FLASH_CMD_>|${L4T_FLASH_CMD}|g" ${release_file}

	# copy ChangeLog.txt into release package
	local changelog_file_name=$(to_upper $(echo ${JETSON_BOARD} | awk -F '-' '{print $1}'))_ChangeLog.txt
	local changelog_file=${CUR_TOP}/../l4t_rk_pkg_tools/${changelog_file_name}
	if [[ -f ${changelog_file} ]]; then
		release_file=${L4T_RELEASE_DIR}/ChangeLog.txt
		echo -e "[INFO] >>> ${release_file}"
		cp ${changelog_file} ${release_file}
		sed -i "s/<_RK_BSP_VER_>/${RK_VER_SUFFIX}/g" ${release_file}
		local RK_RELEASE_DATE=$(echo ${RK_VER_SUFFIX} | cut -b1-8)
		sed -i "s/<_DATE_>/${RK_RELEASE_DATE}/g" ${release_file}
	fi

	# compress
	echo -e "[INFO] Compress into a package ..."
	tar -jcf ${L4T_RELEASE_PKG} ${L4T_RELEASE_DIR}
	#rm -rf ${L4T_RELEASE_DIR}

	echo -e "\n[INFO] Release Done:"
	echo -e "[INFO] >>> ${L4T_RELEASE_PKG}\n"
}

function cmd_bsp_backup()
{
	echo -e "[DEBUG] ${FUNCNAME} $@"

	if [[ ! -d ${L4T_TOP} ]]; then
		echo -e "[ERROR] L4T BSP Directory does exist, please init first."
		return
	fi

	local RK_VER_SUFFIX=$(get_kernel_vermagic_rksuffix $(get_cur_kernel_vermagic))
	if [[ -z ${RK_VER_SUFFIX} ]]; then
		echo -e "[ERROR] Current released kernel version magic doesnot included \"RK_VER_SUFFIX\"\n"
		exit 1
	fi
	local jetson_conf_file=${L4T_TOP}/${JETSON_CONF}.conf
	if [[ ! -f ${jetson_conf_file} ]]; then
		echo -e "[ERROR] The Jetson Board Conf file doesnot exist:"
		echo -e ">>> ${jetson_conf_file}\n"
		exit 1
	fi
	local jetson_dtb=$(conf1_get "${jetson_conf_file}" "DTB_FILE")
	local jetson_dtb_file=${L4T_TOP}/kernel/dtb/${jetson_dtb}
	if [[ ! -f ${jetson_dtb_file} ]]; then
		echo -e "[ERROR] The Jetson Board DTB file doesnot exist:"
		echo -e ">>> ${jetson_dtb_file}\n"
		exit 1
	fi

	local L4T_BACKUP_PKG=Ritrontek_BACKUP_JetPack${JETPACK_VER}_L4T${L4T_VER}_${JETSON_MODULE}_${JETSON_BOARD}_${RK_VER_SUFFIX}.tbz2
	local L4T_BACKUP_DIR=$(echo ${L4T_BACKUP_PKG:0:${#L4T_BACKUP_PKG}-5})
	local L4T_BACKUP_INSTALL_DIR=${L4T_TOP}/tools/backup_restore
	local L4T_BACKUP_IMAGES=${L4T_BACKUP_INSTALL_DIR}/images

	if [[ $# -gt 0 ]]; then
		case $1 in
		"emmc")
			sudo_cmd "sed -i \"s/nvme0n1/mmcblk0/g\" ${L4T_BACKUP_INSTALL_DIR}/nvbackup_partitions.sh"
			sudo_cmd "sed -i \"s/nvme0n1/mmcblk0/g\" ${L4T_BACKUP_INSTALL_DIR}/nvrestore_partitions.sh"
			sudo_cmd "sed -i \"s/nvme0n1/mmcblk0/g\" ${L4T_BACKUP_INSTALL_DIR}/l4t_backup_restore.sh"

			L4T_BSP_FIX_CMD="\tsed -i \"s/nvme0n1/mmcblk0/g\" ../tools/backup_restore/nvbackup_partitions.sh"
			L4T_BSP_FIX_CMD+="\n\tsed -i \"s/nvme0n1/mmcblk0/g\" ../tools/backup_restore/nvrestore_partitions.sh"
			L4T_BSP_FIX_CMD+="\n\tsed -i \"s/nvme0n1/mmcblk0/g\" ../tools/backup_restore/l4t_backup_restore.sh"
			;;
		"nvme")
			sudo_cmd "sed -i \"s/mmcblk0/nvme0n1/g\" ${L4T_BACKUP_INSTALL_DIR}/nvbackup_partitions.sh"
			sudo_cmd "sed -i \"s/mmcblk0/nvme0n1/g\" ${L4T_BACKUP_INSTALL_DIR}/nvrestore_partitions.sh"
			sudo_cmd "sed -i \"s/mmcblk0/nvme0n1/g\" ${L4T_BACKUP_INSTALL_DIR}/l4t_backup_restore.sh"

			L4T_BSP_FIX_CMD="\tsed -i \"s/mmcblk0/nvme0n1/g\" ../tools/backup_restore/nvbackup_partitions.sh"
			L4T_BSP_FIX_CMD+="\n\tsed -i \"s/mmcblk0/nvme0n1/g\" ../tools/backup_restore/nvrestore_partitions.sh"
			L4T_BSP_FIX_CMD+="\n\tsed -i \"s/mmcblk0/nvme0n1/g\" ../tools/backup_restore/l4t_backup_restore.sh"
			;;
		*)
			echo -e "[ERROR] Unsupport bsp backup args: $1."
			return
			;;
		esac
	fi

	if [[ -f ${L4T_BACKUP_PKG} ]]; then
		sudo_cmd "rm -f ${L4T_BACKUP_PKG}"
	fi
	if [[ -d ${L4T_BACKUP_DIR} ]]; then
		sudo_cmd "rm -rf ${L4T_BACKUP_DIR}"
	fi

	local perform_backup="y";
	if [[ -d ${L4T_BACKUP_IMAGES} ]]; then
		echo "[INFO] Backup images directory already exist:"
		echo "[INFO] >>> ${L4T_BACKUP_IMAGES}"
		read -t 10 -p "Using the exist images? (y/N) 10sec:" key

		if [[ ${key} == "Y" || ${key} == "y" ]]; then
			perform_backup="n"
		else
			perform_backup="y"
			echo -e "[INFO] Remove the exist images"
			sudo_cmd "rm -rf ${L4T_BACKUP_IMAGES}"
		fi
	fi

	if [[ ${perform_backup} == "y" ]]; then
		if [[ $(check_device_recovery) != "Y" ]]; then
			echo -e "[INFO] Please connect the Jetson Device to HOST, and put it into recovery mode."
			read -p "Press any key to continue ..." key

			if [[ $(check_device_recovery) != "Y" ]]; then
				echo -e "[ERROR] Jetson Board does not connect, cannot flash, exit!"
				exit 1
			fi
		fi

		local BACKUP_CMD="cd ${L4T_TOP} && ./tools/backup_restore/l4t_backup_restore.sh -b ${JETSON_CONF}"
		echo -e "${BACKUP_CMD}"
		sudo_cmd "${BACKUP_CMD}"
		local ret=$?
		if [[ ${ret} != 0 ]]; then
			echo -e "[ERROR] Backup Device error:"
			echo -e ">>> ${BACKUP_CMD}\n"
			exit 1
		fi
	fi

	if [[ -d ${L4T_BACKUP_DIR} ]]; then
		rm -rf ${L4T_BACKUP_DIR}/*
	else
		mkdir ${L4T_BACKUP_DIR}
	fi

	echo -e "[INFO] Copy backup files ..."

	# conf
	local backup_file=${L4T_BACKUP_DIR}/resources/${JETSON_CONF}.conf
	echo -e "[INFO] >>> ${backup_file}"
	mkdir -p $(dirname ${backup_file})
	cp ${jetson_conf_file} ${backup_file}

	# dtb
	backup_file=${L4T_BACKUP_DIR}/resources/kernel/dtb/${jetson_dtb}
	echo -e "[INFO] >>> ${backup_file}"
	mkdir -p $(dirname ${backup_file})
	cp ${jetson_dtb_file} ${backup_file}

	# backup images
	backup_file=${L4T_BACKUP_DIR}/resources/images.tbz2
	bsp_file=${L4T_TOP}/$(echo ${backup_file} | cut -d/ -f3-)
	echo -e "[INFO] >>> ${backup_file}"
	mkdir -p $(dirname ${backup_file})
	tar -jcf ${backup_file} -C ${L4T_TOP} tools/backup_restore/images

	local L4T_FLASH_CMD="sudo ./tools/backup_restore/l4t_backup_restore.sh -r ${JETSON_CONF}"

	# copy install.sh into backup package
	cp l4t_rk_pkg_tools/install.sh ${L4T_BACKUP_DIR}/install.sh
	sed -i "s|<_L4T_FLASH_CMD_>|${L4T_FLASH_CMD}|g" ${L4T_BACKUP_DIR}/install.sh
	sed -i "s|<_L4T_BSP_FIX_CMD_>|${L4T_BSP_FIX_CMD}|g" ${L4T_BACKUP_DIR}/install.sh
	chmod a+x ${L4T_BACKUP_DIR}/install.sh

	# copy README.md into backup package
	cp l4t_rk_pkg_tools/README.md ${L4T_BACKUP_DIR}/README.md
	sed -i "s/<_JETPACK_VER_>/${JETPACK_VER}/g" ${L4T_BACKUP_DIR}/README.md
	local _L4T_TOP_SUBSTR_="~/$(echo ${L4T_TOP} | cut -d/ -f4-)"
	sed -i "s|<_L4T_TOP_>|${_L4T_TOP_SUBSTR_}|g" ${L4T_BACKUP_DIR}/README.md
	sed -i "s/<_RK_BSP_PKG_DIR_>/${L4T_BACKUP_DIR}/g" ${L4T_BACKUP_DIR}/README.md
	sed -i "s|<_L4T_FLASH_CMD_>|${L4T_FLASH_CMD}|g" ${L4T_BACKUP_DIR}/README.md

	# copy ChangeLog.txt into backup package
	local changelog=l4t_rk_pkg_tools/${JETSON_BOARD}_ChangeLog.txt
	if [[ -f ${changelog} ]]; then
		cp ${changelog} ${L4T_BACKUP_DIR}/ChangeLog.txt
		sed -i "s/<_RK_BSP_VER_>/${RK_VER_SUFFIX}/g" ${L4T_BACKUP_DIR}/ChangeLog.txt
		local RK_BACKUP_DATE=$(echo ${RK_VER_SUFFIX} | cut -b1-8)
		sed -i "s/<_DATE_>/${RK_BACKUP_DATE}/g" ${L4T_BACKUP_DIR}/ChangeLog.txt
	fi

	# compress
	echo -e "\n[INFO] Compress into a package ..."
	echo -e "[INFO] >>> ${L4T_BACKUP_PKG}"
	tar -jcf ${L4T_BACKUP_PKG} ${L4T_BACKUP_DIR}
	#rm -rf ${L4T_BACKUP_DIR}

	echo -e "\n[INFO] Backup Device Done"
}

function cmd_bsp_restore()
{
	echo -e "[DEBUG] ${FUNCNAME} $@"

	if [[ $# -le 0 ]]; then
		echo -e "[ERROR] BSP RESTORE args error.\n"
		exit 1
	fi

	if [[ ! -d ${L4T_TOP} ]]; then
		echo -e "[ERROR] L4T BSP Directory does exist, please init first."
		return
	fi

	local L4T_BACKUP_INSTALL_DIR=${L4T_TOP}/tools/backup_restore
	local L4T_BACKUP_IMAGES=${L4T_BACKUP_INSTALL_DIR}/images
	if [[ $# -gt 1 ]]; then
		case $2 in
		"emmc")
			sudo_cmd "sed -i \"s/nvme0n1/mmcblk0/g\" ${L4T_BACKUP_INSTALL_DIR}/nvbackup_partitions.sh"
			sudo_cmd "sed -i \"s/nvme0n1/mmcblk0/g\" ${L4T_BACKUP_INSTALL_DIR}/nvrestore_partitions.sh"

			L4T_BSP_FIX_CMD="\tsed -i \"s/nvme0n1/mmcblk0/g\" ../tools/backup_restore/nvbackup_partitions.sh"
			L4T_BSP_FIX_CMD+="\n\tsed -i \"s/nvme0n1/mmcblk0/g\" ../tools/backup_restore/nvrestore_partitions.sh"
			;;
		"nvme")
			sudo_cmd "sed -i \"s/mmcblk0/nvme0n1/g\" ${L4T_BACKUP_INSTALL_DIR}/nvbackup_partitions.sh"
			sudo_cmd "sed -i \"s/mmcblk0/nvme0n1/g\" ${L4T_BACKUP_INSTALL_DIR}/nvrestore_partitions.sh"

			L4T_BSP_FIX_CMD="\tsed -i \"s/mmcblk0/nvme0n1/g\" ../tools/backup_restore/nvbackup_partitions.sh"
			L4T_BSP_FIX_CMD+="\n\tsed -i \"s/mmcblk0/nvme0n1/g\" ../tools/backup_restore/nvrestore_partitions.sh"
			;;
		*)
			echo -e "[ERROR] Unsupport bsp backup args: $1."
			return
			;;
		esac
	fi

	if [[ $(dirname $1) != "." ]]; then
		echo -e "[ERROR] L4T_BACKUP_PKG/L4T_BACKUP_DIR must stay in current work directory.\n"
		exit 1
	fi
	if [[ $(basename $1) =~ ^.*\.tbz2$ ]]; then
		local L4T_BACKUP_PKG=$(basename $1)
		local L4T_BACKUP_DIR=$(echo ${L4T_BACKUP_PKG:0:${#L4T_BACKUP_PKG}-5})
	else
		local L4T_BACKUP_DIR=$(basename $1)
		local L4T_BACKUP_PKG=$(basename $1).tbz2
	fi
	if [[ ! ${L4T_BACKUP_PKG} =~ \
		^Ritrontek_BACKUP_JetPack${JETPACK_VER}_L4T${L4T_VER}_${JETSON_BOARD}_[0-9]{14}\.tbz2$ ]]; then

		echo -e "[ERROR] BACKUP package donot match current L4T BSP, please confirm:"
		echo -e ">>> ${L4T_BACKUP_PKG}\n"
		exit 1
	fi
	if [[ ! -d ${L4T_BACKUP_DIR} ]]; then
		tar -jxf ${L4T_BACKUP_PKG}
	fi

	if [[ -d ${L4T_BACKUP_IMAGES} ]]; then
		echo "[INFO] Remove the exist images directory:"
		echo ">>> ${L4T_BACKUP_IMAGES}"
		sudo_cmd "rm -rf ${L4T_BACKUP_IMAGES}"
	fi

	local BACKUP_RES_PATH=$(abs_path "${L4T_BACKUP_DIR}/resources")
	if [[ -d ${BACKUP_RES_PATH} ]]; then
		local BACKUP_RES_PATH_LEVEL=$(abs_path_level ${BACKUP_RES_PATH})
		echo "[INFO] Install backup package ..."
		traverse ${BACKUP_RES_PATH} traverse_filter_filename_r ^README traverse_exec_install ${BACKUP_RES_PATH_LEVEL} ${L4T_TOP}
		echo "[INFO] Install Done."
	fi

	read -t 10 -p "Perform restore to device now? (Y/n) 10sec:" key
	if [[ ${key} == "N" || ${key} == "n" ]]; then
		echo -e "[INFO] Exit"
		exit 0
	fi

	if [[ $(check_device_recovery) != "Y" ]]; then
		echo -e "[INFO] Please connect the Jetson Device to HOST, and put it into recovery mode."
		read -p "Press any key to continue ..." key

		if [[ $(check_device_recovery) != "Y" ]]; then
			echo -e "[ERROR] Jetson Board does not connect, cannot flash, exit!"
			exit 1
		fi
	fi

	local RESTORE_CMD="cd ${L4T_TOP} && ./tools/backup_restore/l4t_backup_restore.sh -r ${JETSON_BOARD}"
	echo -e "${RESTORE_CMD}"
	sudo_cmd "${RESTORE_CMD}"
	local ret=$?
	if [[ ${ret} != 0 ]]; then
		echo -e "[ERROR] Restore Device error:"
		echo -e ">>> ${RESTORE_CMD}\n"
		exit 1
	fi

	echo -e "\n[INFO] Restore Device Done"
}
